package com.linpq.road.util;

import com.linpq.road.domain.RdRoadSectionLane;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author GothamFish
 * @Date 2021/07/30/9:54
 * @Description 路桩序列号生成工具类
 * 序列号生成规则
 * 路桩序列号为22位数字，1-4位为管养单位编码；5-8位为高速编码；
 * 9-12位为高速路段编码；13位为上下行信息（0为上行，1为下行）；
 * 14位表示车道（0表示应急道，1表示左1道，2表示左二道，3表示左三道，4表示左四道）；
 * 15-21位表示路桩编号，如K1+100，为0001100；22位为校验位：规则暂定为 (前21转char求和之后的个位数值) ；
 */
public class SerialNumberGenUtil {
    public static final String PREFIX_PILE_NUMBER = "K";
    public static final Character SPILT_PILE_NUMBER = '+';
    public static final String UP_ROAD = "0";
    public static final String DOWN_ROAD = "1";
    public static final int START_LANE = 1;
    //public static final int EMERGENCY_LANE = 0;

    /**
     * 生成某个路段的所有路桩序列号，正常为初始化时调用
     *
     * @param managementUnitSerialNumber 管养单位编码
     * @param highSpeedRoadSerialNumber  高速公路编码
     * @param roadSectionSerialNumber    路段编码
     * @param startPileNumber            起始桩号
     * @param endPileNumber              截止桩号
     * @param length                     路桩间隔
     * @param laneSymmetry               路段车道是否上下行数量一致(数量一致则为true否则为false)
     * @param sectionLaneNumber          路段车道数量：对称则输入单个数量至少为2(基础车道不包括应急车道即 0)，不对称则初始化需要输入两个值，取最小的传进序列号生成
     * @param roadSectionLaneList        路段车道集合:路段初始化->初始化车道（将路段起止桩号正置的为上行，反置的为下行然后将这基础车道集合传递进来生成路桩序列号）
     * @return
     */
    public static List<Map<String, String>> generateSerialNumber(String managementUnitSerialNumber, String highSpeedRoadSerialNumber,
                                                                 String roadSectionSerialNumber, String startPileNumber,
                                                                 String endPileNumber, Integer length, boolean laneSymmetry,
                                                                 Integer sectionLaneNumber, List<RdRoadSectionLane> roadSectionLaneList) {
        List<Map<String, String>> roadStakeList = new ArrayList<Map<String, String>>();
        //转换高速路段编号为指定格式（四位数字符串）
        String sectionSerialNumberFormat = String.format("%04d", Integer.valueOf(roadSectionSerialNumber));
        //一致的编码,因为初始化相对来说并不太需要关注线程安全，所以使用速度更快的StringBuilder
        StringBuilder baseBuilder = new StringBuilder(managementUnitSerialNumber + highSpeedRoadSerialNumber + sectionSerialNumberFormat);
        //上下行区分开，以基础车道数量为单位分开进行路桩初始化
        for (int i = START_LANE; i <= sectionLaneNumber; i++) {
            List<Map<String, String>> upRoadStakeList = genNumberPassLaneDivision(baseBuilder, startPileNumber,
                    endPileNumber, length, i);

            List<Map<String, String>> downRoadStakeList = genNumberPassLaneDivision(baseBuilder,
                    endPileNumber, startPileNumber, length, i);
            roadStakeList.addAll(upRoadStakeList);
            roadStakeList.addAll(downRoadStakeList);
        }
        //根据laneSymmetry判断，如果上下行数量不一致，则说明有额外车道，则遍历车道集合，将额外车道的路桩进行初始化
        if (!laneSymmetry) {
            for (RdRoadSectionLane roadSectionLane : roadSectionLaneList) {
                for (int i = sectionLaneNumber + 1; i <= roadSectionLane.getLaneNumber(); i++) {
                    List<Map<String, String>> extraRoadStakeList = genNumberPassLaneDivision(baseBuilder,
                            roadSectionLane.getStartPileNumber(),
                            roadSectionLane.getEndPileNumber(), length, i);
                    roadStakeList.addAll(extraRoadStakeList);
                }
            }
        }
        return roadStakeList;
    }

    /**
     * 转换起止路桩编号为七位数字的格式,传入的路桩编号必须符合开头大写的 K 中间用 + 号连接的格式，+号前最多4位，+号后 最多3位
     *
     * @param pileNumber
     * @return
     */
    public static Integer parsePileNumber(String pileNumber) {
        String replace = pileNumber.replace(PREFIX_PILE_NUMBER, "").replace("+", "");
        return Integer.valueOf(replace);
    }


    /**
     * 以车道为基础单位，生成该车道的路桩序列号(具体是完成判断上下行和对应生成路桩编号即不断叠加)，初始化时，主方法会重复调用，
     * 平时给路段添加额外车道时就调用该方法而不是主方法，注意传参的baseBuilder
     *
     * @param baseBuilder           一致的编码（管养单位编码，高速公路编码，路段编码，路段编码不足四位的需补零）
     * @param startPileNumber
     * @param endPileNumber
     * @param length
     * @param lanePosition
     * @return   第几车道
     */
    public static List<Map<String, String>> genNumberPassLaneDivision(StringBuilder baseBuilder, String startPileNumber,
                                                                      String endPileNumber, Integer length, Integer lanePosition) {
        Integer startPileNumberFormat = parsePileNumber(startPileNumber);
        Integer endPileNumberFormat = parsePileNumber(endPileNumber);
        List<Map<String, String>> roadStakeList = new ArrayList<Map<String, String>>();
        String upOrDown = UP_ROAD;
        int beginIndex = startPileNumberFormat;
        int lastIndex = endPileNumberFormat;
        Integer interval = length;
        //根据桩号大小判断上下行，startPileNumberFormat > endPileNumberFormat 为下行则上下行位和间隔做出更改,
        // 且将循环起止点更改，无论上下行，循环与编号是分开的，循环都是由小到大
        if (startPileNumberFormat > endPileNumberFormat) {
            upOrDown = DOWN_ROAD;
            interval = -length;
            beginIndex = endPileNumberFormat;
            lastIndex = startPileNumberFormat;
        }
        Integer nowPileNumber = startPileNumberFormat;
        String nowPileNumberFormat = null;
        for (int i = beginIndex; i <= lastIndex; ) {
            HashMap<String, String> map = new HashMap<>();
            StringBuilder serialNumber = new StringBuilder();
            nowPileNumberFormat = String.format("%07d",nowPileNumber);
            serialNumber = serialNumber.append(baseBuilder).append(upOrDown).append(lanePosition).append(nowPileNumberFormat);
            String ultimateSerialNumber = serialNumber + String.valueOf(suffixNumber(serialNumber));
            map.put("roadStakeSerialNumber", ultimateSerialNumber);
            roadStakeList.add(map);
            i += length;
            //当最后一个路桩加完间隔长度超过最终长度时，将编号最大值赋值给循环标志位，将截止桩编号减去间隔，赋值给现编号，完成截止桩序列号的生成
            if (i > lastIndex && i < lastIndex + length) {
                i = lastIndex;
                nowPileNumber = endPileNumberFormat - interval;
            }
            nowPileNumber += interval;
        }
        return roadStakeList;
    }

    /**
     * 校验位生成
     *
     * @param serialNumber
     * @return 规则：前21转char求和之后的个位数值
     */
    public static Integer suffixNumber(StringBuilder serialNumber) {
        int suffixNumber = 0;
        for (int i = 0; i < serialNumber.length(); i++) {
            char c = serialNumber.charAt(i);
            suffixNumber += c;
        }
        return suffixNumber % 10;
    }



    /**
     *
     * 检查序列号：
     * 是否为22位并且是否为空。
     * 13位为上下行并且14位表示车道
     *
     * @param serialNumber 序列号
     * @return true，false
     */
    public static boolean checkSerialNumber(String serialNumber) {
        if (serialNumber.length() != 22 && !StringUtils.isEmpty(serialNumber)) {
            return false;
        }

        if (Integer.valueOf(serialNumber.substring(12,13)) > 1 || Integer.valueOf(serialNumber.substring(13,14)) > 4) {
            return false;
        }
        return true;
    }


    /**
     *
     * @param pileNumber 15-21路桩编号
     * @return 解析后的路桩号
     */
    public static String parsingPileNumber(String pileNumber) {
        String parsePileNumber = PREFIX_PILE_NUMBER + Integer.valueOf(pileNumber.substring(0, pileNumber.length() - 3)) + SPILT_PILE_NUMBER + pileNumber.substring(pileNumber.length() - 3);
        return parsePileNumber;
    }

    /**
     * 给路道加点颜色
     * @param str14 14车道编号
     * @return 路道信息
     */
    public static String lane(String str14) {
        str14 = str14.equals("0")?"应急车道":"左"+str14+"道";
        return str14;
    }

}
